package m3f.factorization;

import java.util.Hashtable;

import org.jblas.DoubleMatrix;

import m3f.computing.ConcurrentTemplate;
import m3f.data.MultimodalDataProvider;
import m3f.io.DenseMatrixWriter;
import m3f.matrix.Minibatch;

public class ConcurrentMatrixWriter extends ConcurrentTemplate{
	
	private MultimodalDataProvider trainingData;
	private DenseMatrixWriter writer;
	private DoubleMatrix P;
	private DoubleMatrix Q;
	private DoubleMatrix G;
	private double omega;
	private Hashtable<Integer, DoubleMatrix> cache;
	private int minibatchToWrite;
	
	public ConcurrentMatrixWriter(MultimodalDataProvider data, DenseMatrixWriter writer, DoubleMatrix P, DoubleMatrix Q, DoubleMatrix G, double omega){
		super(data.matrixRows()/data.getMinibatchSize() + 1);
		this.trainingData = data;
		this.writer = writer;
		this.P = P;
		this.Q = Q;
		this.G = G;
		this.omega = omega;
		cache = new Hashtable<Integer, DoubleMatrix>();
		minibatchToWrite = 0;
	}

	@Override
	public void singleOperation(int reg) {
		Minibatch V, T;
		synchronized(trainingData){
			V = trainingData.nextVisual();
			T = trainingData.nextTextual();
		}
		DoubleMatrix H = OnlineJointFactorization.latentRepresentation(V, T, P, Q, G, omega);
		DoubleMatrix hs = V.matrix().columnSums();
		for(int n = 0; n < hs.columns; n++){
			if(hs.get(n) == 0.0D){
				System.err.println("Unexpected Zero Vector!!! Position:" + n + " at minibatch " + V.getId());
			}
		}
		cache.put(V.getId(), H);
		updateFile();
	}
	
	private synchronized void updateFile(){
		while(cache.keySet().contains(minibatchToWrite)){
			System.out.println("Writing minibatch " + minibatchToWrite);
			DoubleMatrix H = cache.remove(minibatchToWrite);
			writer.appendMatrix(H, true);
			minibatchToWrite++;
		}
	}

}
